package Tests
{
	import Box2D.Collision.Shapes.b2EdgeShape;
	import Box2D.Collision.Shapes.b2PolygonShape;
	import Box2D.Common.Math.b2Math;
	import Box2D.Common.Math.b2Vec2;
	import Box2D.Dynamics.b2Body;
	import Box2D.Dynamics.b2BodyDef;
	import Box2D.Dynamics.b2BodyType;
	import Box2D.Dynamics.b2Contact;
	import Box2D.Dynamics.b2ContactImpulse;
	import Box2D.Dynamics.b2Fixture;
	
	import Framework.Test;
	
	public class Breakable extends Test
	{
		private static const e_count:int = 7;
		private var m_body1:b2Body;
		private var m_velocity:b2Vec2;
		private var m_angularVelocity:Number;
		private var m_shape1:b2PolygonShape = new b2PolygonShape;
		private var m_shape2:b2PolygonShape = new b2PolygonShape;
		private var m_piece1:b2Fixture;
		private var m_piece2:b2Fixture;
		private var m_broke:Boolean;
		private var m_break:Boolean;
		public function Breakable()
		{
			super();
			createGround();
			createBodies();
			m_break = false;
			m_broke = false;
		}
		private function createGround():void{
			var shape:b2EdgeShape = new b2EdgeShape;
			shape.Set(new b2Vec2(-40,0),new b2Vec2(40,0));
			m_groundBody.CreateFixtureByShape(shape,0);
		}
		private function createBodies():void{
			var bd:b2BodyDef = new b2BodyDef;
			bd.type = b2BodyType.b2_dynamicBody;
			bd.position.Set(0.0, 40.0);
			bd.angle = 0.25 * Math.PI;
			m_body1 = m_world.CreateBody(bd);
			
			m_shape1.SetAsBoxByCenter(0.5, 0.5, new b2Vec2(-0.5, 0.0), 0.0);
			m_piece1 = m_body1.CreateFixtureByShape(m_shape1, 1.0);
			
			m_shape2.SetAsBoxByCenter(0.5, 0.5, new b2Vec2(0.5, 0.0), 0.0);
			m_piece2 = m_body1.CreateFixtureByShape(m_shape2, 1.0);			
		}
		public override function PostSolve(contact:b2Contact, impulse:b2ContactImpulse):void{
			if (m_broke)
			{
				// The body already broke.
				return;
			}
			
			// Should the body break?
			var count:int = contact.GetManifold().pointCount;
			
			var maxImpulse:Number = 0.0;
			for (var i:int = 0; i < count; ++i)
			{
				maxImpulse = Math.max(maxImpulse, impulse.normalImpulses[i]);
			}
			
			if (maxImpulse > 40.0)
			{
				// Flag the body for breaking.
				m_break = true;
			}			
		}
		private function Break():void
		{
			// Create two bodies from one.
			var body1:b2Body = m_piece1.GetBody();
			var center:b2Vec2 = body1.GetWorldCenter();
			
			body1.DestroyFixture(m_piece2);
			m_piece2 = null;
			
			var bd:b2BodyDef = new b2BodyDef;
			bd.type = b2BodyType.b2_dynamicBody;
			bd.position = body1.GetPosition();
			bd.angle = body1.GetAngle();
			
			var body2:b2Body = m_world.CreateBody(bd);
			m_piece2 = body2.CreateFixtureByShape(m_shape2, 1.0);
			
			// Compute consistent velocities for new bodies based on
			// cached velocity.
			var center1:b2Vec2 = body1.GetWorldCenter();
			var center2:b2Vec2 = body2.GetWorldCenter();
			
			var velocity1:b2Vec2 = m_velocity.Add(b2Math.CrossFV(m_angularVelocity, center1.Subtract(center)));
			var velocity2:b2Vec2 = m_velocity.Add(b2Math.CrossFV(m_angularVelocity, center2.Subtract(center)));
			
			body1.SetAngularVelocity(m_angularVelocity);
			body1.SetLinearVelocity(velocity1);
			
			body2.SetAngularVelocity(m_angularVelocity);
			body2.SetLinearVelocity(velocity2);
		}
		public override function Step():void{
			if (m_break)
			{
				Break();
				m_broke = true;
				m_break = false;
			}
			
			// Cache velocities to improve movement on breakage.
			if (m_broke == false)
			{
				m_velocity = m_body1.GetLinearVelocity();
				m_angularVelocity = m_body1.GetAngularVelocity();
			}
			
			super.Step();			
		}
	}
}